<!-- HTML header for doxygen 1.8.6-->
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
<meta name="generator" content="Doxygen 1.8.13"/>
<title>OpenCV: Calibration with ArUco and ChArUco</title>
<link href="../../opencv.ico" rel="shortcut icon" type="image/x-icon" />
<link href="../../tabs.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="../../jquery.js"></script>
<script type="text/javascript" src="../../dynsections.js"></script>
<script type="text/javascript" src="../../tutorial-utils.js"></script>
<link href="../../search/search.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="../../search/searchdata.js"></script>
<script type="text/javascript" src="../../search/search.js"></script>
<script type="text/x-mathjax-config">
  MathJax.Hub.Config({
    extensions: ["tex2jax.js", "TeX/AMSmath.js", "TeX/AMSsymbols.js"],
    jax: ["input/TeX","output/HTML-CSS"],
});
//<![CDATA[
MathJax.Hub.Config(
{
  TeX: {
      Macros: {
          matTT: [ "\\[ \\left|\\begin{array}{ccc} #1 & #2 & #3\\\\ #4 & #5 & #6\\\\ #7 & #8 & #9 \\end{array}\\right| \\]", 9],
          fork: ["\\left\\{ \\begin{array}{l l} #1 & \\mbox{#2}\\\\ #3 & \\mbox{#4}\\\\ \\end{array} \\right.", 4],
          forkthree: ["\\left\\{ \\begin{array}{l l} #1 & \\mbox{#2}\\\\ #3 & \\mbox{#4}\\\\ #5 & \\mbox{#6}\\\\ \\end{array} \\right.", 6],
          forkfour: ["\\left\\{ \\begin{array}{l l} #1 & \\mbox{#2}\\\\ #3 & \\mbox{#4}\\\\ #5 & \\mbox{#6}\\\\ #7 & \\mbox{#8}\\\\ \\end{array} \\right.", 8],
          vecthree: ["\\begin{bmatrix} #1\\\\ #2\\\\ #3 \\end{bmatrix}", 3],
          vecthreethree: ["\\begin{bmatrix} #1 & #2 & #3\\\\ #4 & #5 & #6\\\\ #7 & #8 & #9 \\end{bmatrix}", 9],
          cameramatrix: ["#1 = \\begin{bmatrix} f_x & 0 & c_x\\\\ 0 & f_y & c_y\\\\ 0 & 0 & 1 \\end{bmatrix}", 1],
          distcoeffs: ["(k_1, k_2, p_1, p_2[, k_3[, k_4, k_5, k_6 [, s_1, s_2, s_3, s_4[, \\tau_x, \\tau_y]]]]) \\text{ of 4, 5, 8, 12 or 14 elements}"],
          distcoeffsfisheye: ["(k_1, k_2, k_3, k_4)"],
          hdotsfor: ["\\dots", 1],
          mathbbm: ["\\mathbb{#1}", 1],
          bordermatrix: ["\\matrix{#1}", 1]
      }
  }
}
);
//]]>
</script><script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js"></script>
<link href="../../doxygen.css" rel="stylesheet" type="text/css" />
<link href="../../stylesheet.css" rel="stylesheet" type="text/css"/>
</head>
<body>
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<div id="titlearea">
<!--#include virtual="/google-search.html"-->
<table cellspacing="0" cellpadding="0">
 <tbody>
 <tr style="height: 56px;">
  <td id="projectlogo"><img alt="Logo" src="../../opencv-logo-small.png"/></td>
  <td style="padding-left: 0.5em;">
   <div id="projectname">OpenCV
   &#160;<span id="projectnumber">4.5.2</span>
   </div>
   <div id="projectbrief">Open Source Computer Vision</div>
  </td>
 </tr>
 </tbody>
</table>
</div>
<!-- end header part -->
<!-- Generated by Doxygen 1.8.13 -->
<script type="text/javascript">
var searchBox = new SearchBox("searchBox", "../../search",false,'Search');
</script>
<script type="text/javascript" src="../../menudata.js"></script>
<script type="text/javascript" src="../../menu.js"></script>
<script type="text/javascript">
$(function() {
  initMenu('../../',true,false,'search.php','Search');
  $(document).ready(function() { init_search(); });
});
</script>
<div id="main-nav"></div>
<!-- window showing the filter options -->
<div id="MSearchSelectWindow"
     onmouseover="return searchBox.OnSearchSelectShow()"
     onmouseout="return searchBox.OnSearchSelectHide()"
     onkeydown="return searchBox.OnSearchSelectKey(event)">
</div>

<!-- iframe showing the search results (closed by default) -->
<div id="MSearchResultsWindow">
<iframe src="javascript:void(0)" frameborder="0" 
        name="MSearchResults" id="MSearchResults">
</iframe>
</div>

<div id="nav-path" class="navpath">
  <ul>
<li class="navelem"><a class="el" href="../../d3/d81/tutorial_contrib_root.html">Tutorials for contrib modules</a></li><li class="navelem"><a class="el" href="../../d9/d6d/tutorial_table_of_content_aruco.html">ArUco marker detection (aruco module)</a></li>  </ul>
</div>
</div><!-- top -->
<div class="header">
  <div class="headertitle">
<div class="title">Calibration with ArUco and ChArUco </div>  </div>
</div><!--header-->
<div class="contents">
<div class="textblock"><p>The ArUco module can also be used to calibrate a camera. Camera calibration consists in obtaining the camera intrinsic parameters and distortion coefficients. This parameters remain fixed unless the camera optic is modified, thus camera calibration only need to be done once.</p>
<p>Camera calibration is usually performed using the OpenCV <code><a class="el" href="../../d9/d0c/group__calib3d.html#ga3207604e4b1a1758aa66acb6ed5aa65d" title="Finds the camera intrinsic and extrinsic parameters from several views of a calibration pattern...">calibrateCamera()</a></code> function. This function requires some correspondences between environment points and their projection in the camera image from different viewpoints. In general, these correspondences are obtained from the corners of chessboard patterns. See <code><a class="el" href="../../d9/d0c/group__calib3d.html#ga3207604e4b1a1758aa66acb6ed5aa65d" title="Finds the camera intrinsic and extrinsic parameters from several views of a calibration pattern...">calibrateCamera()</a></code> function documentation or the OpenCV calibration tutorial for more detailed information.</p>
<p>Using the ArUco module, calibration can be performed based on ArUco markers corners or ChArUco corners. Calibrating using ArUco is much more versatile than using traditional chessboard patterns, since it allows occlusions or partial views.</p>
<p>As it can be stated, calibration can be done using both, marker corners or ChArUco corners. However, it is highly recommended using the ChArUco corners approach since the provided corners are much more accurate in comparison to the marker corners. Calibration using a standard Board should only be employed in those scenarios where the ChArUco boards cannot be employed because of any kind of restriction.</p>
<h2>Calibration with ChArUco Boards </h2>
<p>To calibrate using a ChArUco board, it is necessary to detect the board from different viewpoints, in the same way that the standard calibration does with the traditional chessboard pattern. However, due to the benefits of using ChArUco, occlusions and partial views are allowed, and not all the corners need to be visible in all the viewpoints.</p>
<div class="image">
<img src="../../charucocalibration.png" alt="charucocalibration.png"/>
<div class="caption">
ChArUco calibration viewpoints</div></div>
<p> The function to calibrate is <code><a class="el" href="../../d9/d6a/group__aruco.html#ga54cf81c2e39119a84101258338aa7383" title="Calibrate a camera using Charuco corners. ">calibrateCameraCharuco()</a></code>. Example:</p>
<div class="fragment"><div class="line"><a class="code" href="../../dc/d84/group__core__basic.html#ga6395ca871a678020c4a31fadf7e8cc63">cv::Ptr&lt;aruco::CharucoBoard&gt;</a> board = ... <span class="comment">// create charuco board</span></div><div class="line"><a class="code" href="../../d6/d50/classcv_1_1Size__.html">cv::Size</a> imgSize = ... <span class="comment">// camera image size</span></div><div class="line"></div><div class="line">std::vector&lt;std::vector&lt;cv::Point2f&gt;&gt; allCharucoCorners;</div><div class="line">std::vector&lt;std::vector&lt;int&gt;&gt; allCharucoIds;</div><div class="line"><span class="comment">// Detect charuco board from several viewpoints and fill allCharucoCorners and allCharucoIds</span></div><div class="line">...</div><div class="line">...</div><div class="line"></div><div class="line"><span class="comment">// After capturing in several viewpoints, start calibration</span></div><div class="line"><a class="code" href="../../d3/d63/classcv_1_1Mat.html">cv::Mat</a> cameraMatrix, distCoeffs;</div><div class="line">std::vector&lt;cv::Mat&gt; rvecs, tvecs;</div><div class="line"><span class="keywordtype">int</span> calibrationFlags = ... <span class="comment">// Set calibration flags (same than in calibrateCamera() function)</span></div><div class="line"></div><div class="line"><span class="keywordtype">double</span> repError = <a class="code" href="../../d9/d6a/group__aruco.html#ga54cf81c2e39119a84101258338aa7383">cv::aruco::calibrateCameraCharuco</a>(allCharucoCorners, allCharucoIds, board, imgSize, cameraMatrix, distCoeffs, rvecs, tvecs, calibrationFlags);</div></div><!-- fragment --><p>The ChArUco corners and ChArUco identifiers captured on each viewpoint are stored in the vectors <code>allCharucoCorners</code> and <code>allCharucoIds</code>, one element per viewpoint.</p>
<p>The <code><a class="el" href="../../d9/d6a/group__aruco.html#ga54cf81c2e39119a84101258338aa7383" title="Calibrate a camera using Charuco corners. ">calibrateCameraCharuco()</a></code> function will fill the <code>cameraMatrix</code> and <code>distCoeffs</code> arrays with the camera calibration parameters. It will return the reprojection error obtained from the calibration. The elements in <code>rvecs</code> and <code>tvecs</code> will be filled with the estimated pose of the camera (respect to the ChArUco board) in each of the viewpoints.</p>
<p>Finally, the <code>calibrationFlags</code> parameter determines some of the options for the calibration. Its format is equivalent to the flags parameter in the OpenCV <code><a class="el" href="../../d9/d0c/group__calib3d.html#ga3207604e4b1a1758aa66acb6ed5aa65d" title="Finds the camera intrinsic and extrinsic parameters from several views of a calibration pattern...">calibrateCamera()</a></code> function.</p>
<p>A full working example is included in the <code>calibrate_camera_charuco.cpp</code> inside the module samples folder.</p>
<p>Note: The samples now take input via commandline via the <a href="http://docs.opencv.org/trunk/d0/d2e/classcv_1_1CommandLineParser.html#gsc.tab=0">OpenCV Commandline Parser</a>. For this file the example parameters will look like </p><div class="fragment"><div class="line">_output path_<span class="stringliteral">&quot; -dp=&quot;</span>_path_/detector_params.yml<span class="stringliteral">&quot; -w=5 -h=7 -sl=0.04 -ml=0.02 -d=10</span></div></div><!-- fragment --><h2>Calibration with ArUco Boards </h2>
<p>As it has been stated, it is recommended the use of ChAruco boards instead of ArUco boards for camera calibration, since ChArUco corners are more accurate than marker corners. However, in some special cases it must be required to use calibration based on ArUco boards. For these cases, the <code><a class="el" href="../../d9/d6a/group__aruco.html#gacf03e5afb0bc516b73028cf209984a06" title="Calibrate a camera using aruco markers. ">calibrateCameraAruco()</a></code> function is provided. As in the previous case, it requires the detections of an ArUco board from different viewpoints.</p>
<div class="image">
<img src="../../arucocalibration.png" alt="arucocalibration.png"/>
<div class="caption">
ArUco calibration viewpoints</div></div>
<p> Example of <code><a class="el" href="../../d9/d6a/group__aruco.html#gacf03e5afb0bc516b73028cf209984a06" title="Calibrate a camera using aruco markers. ">calibrateCameraAruco()</a></code> use:</p>
<div class="fragment"><div class="line"><a class="code" href="../../dc/d84/group__core__basic.html#ga6395ca871a678020c4a31fadf7e8cc63">cv::Ptr&lt;aruco::Board&gt;</a> board = ... <span class="comment">// create aruco board</span></div><div class="line"><a class="code" href="../../d6/d50/classcv_1_1Size__.html">cv::Size</a> imgSize = ... <span class="comment">// camera image size</span></div><div class="line"></div><div class="line">std::vector&lt;std::vector&lt;cv::Point2f&gt;&gt; allCornersConcatenated;</div><div class="line">std::vector&lt;int&gt; allIdsConcatenated;</div><div class="line">std::vector&lt;int&gt; markerCounterPerFrame;</div><div class="line"><span class="comment">// Detect aruco board from several viewpoints and fill allCornersConcatenated, allIdsConcatenated and markerCounterPerFrame</span></div><div class="line">...</div><div class="line">...</div><div class="line"></div><div class="line"><span class="comment">// After capturing in several viewpoints, start calibration</span></div><div class="line"><a class="code" href="../../d3/d63/classcv_1_1Mat.html">cv::Mat</a> cameraMatrix, distCoeffs;</div><div class="line">std::vector&lt;cv::Mat&gt; rvecs, tvecs;</div><div class="line"><span class="keywordtype">int</span> calibrationFlags = ... <span class="comment">// Set calibration flags (same than in calibrateCamera() function)</span></div><div class="line"></div><div class="line"><span class="keywordtype">double</span> repError = <a class="code" href="../../d9/d6a/group__aruco.html#gacf03e5afb0bc516b73028cf209984a06">cv::aruco::calibrateCameraAruco</a>(allCornersConcatenated, allIdsConcatenated, markerCounterPerFrame, board, imgSize, cameraMatrix, distCoeffs, rvecs, tvecs, calibrationFlags);</div></div><!-- fragment --><p>In this case, and contrary to the <code><a class="el" href="../../d9/d6a/group__aruco.html#ga54cf81c2e39119a84101258338aa7383" title="Calibrate a camera using Charuco corners. ">calibrateCameraCharuco()</a></code> function, the detected markers on each viewpoint are concatenated in the arrays <code>allCornersConcatenated</code> and <code>allCornersConcatenated</code> (the first two parameters). The third parameter, the array <code>markerCounterPerFrame</code>, indicates the number of marker detected on each viewpoint. The rest of parameters are the same than in <code><a class="el" href="../../d9/d6a/group__aruco.html#ga54cf81c2e39119a84101258338aa7383" title="Calibrate a camera using Charuco corners. ">calibrateCameraCharuco()</a></code>, except the board layout object which does not need to be a <code>CharucoBoard</code> object, it can be any <code>Board</code> object.</p>
<p>A full working example is included in the <code>calibrate_camera.cpp</code> inside the module samples folder.</p>
<p>Note: The samples now take input via commandline via the <a href="http://docs.opencv.org/trunk/d0/d2e/classcv_1_1CommandLineParser.html#gsc.tab=0">OpenCV Commandline Parser</a>. For this file the example parameters will look like </p><div class="fragment"><div class="line"><span class="stringliteral">&quot;_path_/calib.txt&quot;</span> -w=5 -h=7 -l=100 -s=10 -d=10</div></div><!-- fragment --> </div></div><!-- contents -->
<!-- HTML footer for doxygen 1.8.6-->
<!-- start footer part -->
<hr class="footer"/><address class="footer"><small>
Generated on Fri Apr 2 2021 11:36:38 for OpenCV by &#160;<a href="http://www.doxygen.org/index.html">
<img class="footer" src="../../doxygen.png" alt="doxygen"/>
</a> 1.8.13
</small></address>
<script type="text/javascript">
//<![CDATA[
addTutorialsButtons();
//]]>
</script>
</body>
</html>
